#pragma once

#include "runner.h"
#include "compiler.h"
#include "../comm/util.h"
#include "../comm/Log.h"
#include <jsoncpp/json/json.h>

// 编译运行功能整合,只负责执行传入代码的编译与运行(生成的文件名必须唯一)
// 并且需要实现对输入参数进行json反序列化的功能
// 将错误信息返回给输出参数
namespace ns_CompileAndRun
{
    using namespace ns_compile;
    using namespace ns_run;
    using namespace ns_log;
    using namespace ns_util;
    // using namespace Json;

    class compile_and_runner
    {
    public:
        compile_and_runner() {}
        ~compile_and_runner() {}

        static void RemoveTempFile(const string &file_name)
        {
            // unlink函数-》删除一个文件 成功返回0 失败返回-1并设置errno

            string _compile_err = path_util::Compile_err(file_name);
            unlink(_compile_err.c_str());

            string _src = path_util::Src(file_name);
            unlink(_src.c_str());

            string _exe = path_util::Exe(file_name);
            unlink(_exe.c_str());

            string _stdin = path_util::Stdin(file_name);
            unlink(_stdin.c_str());

            string _stdout = path_util::Stdout(file_name);
            unlink(_stdout.c_str());

            string _stderr = path_util::Stderr(file_name);
            unlink(_stderr.c_str());
        }

    public:
        // code:
        // >0: 代码运行时收到信号
        // <0:代码为空+编译错误+内部代码出错
        // =0: 编译运行通过
        static string CodeToInfo(int code_status, const string &file_name)
        {
            string ret_info;
            switch (code_status)
            {
            case 0:
                ret_info = "代码编译运行通过";
                break;
            case -1:
                ret_info = "传入代码为空";
                break;
            case -2:
                ret_info = "未知错误";
                break;
            case -3:
                ret_info = file_util::ReadFile(path_util::Compile_err(file_name)).c_str();
                break;
            case SIGABRT: // 6
                ret_info = "超出内存限制";
                break;
            case SIGXCPU: // 24
                ret_info = "超出时间限制";
                break;
            case SIGFPE: // 8
                ret_info = "浮点数溢出";
                break;
            default:
                ret_info = "未知错误,code_status = " + to_string(code_status);
                break;
            }
            return ret_info;
        }

    public:
        //************************************************************************
        // 输入参数:
        // json_in:其中的序列化字段包括->
        // {code, 输入的自测用例, cpu_limit, mem_limit}
        //
        // 输出参数:
        // json_out:存放的是输出信息
        // status: 执行退出状态码
        // status_reason: 状态码所对应的退出原因
        // stdout+stderr: 程序运行的退出结果
        //************************************************************************
        static void StartCompileAndRunner(const string &json_in, string *json_out)
        {
            // 1.进行反序列化到Value类的in对象中
            Json::Value in;
            Json::Reader reader;
            reader.parse(json_in, in);

            // 2.进行解析
            string code = in["code"].asString();
            string input = in["input"].asString();
            int cpu_limit = in["cpu_limit"].asInt();
            int mem_limit = in["mem_limit"].asInt();

            //***处理返回值

            // goto语句会跳转中间的代码段, 所以不能创建变量
            Json::Value out;
            int code_status;  // 错误码
            string file_name; // 生成的唯一代码文件名
            int run_ret;      // 代码运行的返回值

            if (code.empty())
            {
                code_status = -1; // 代码为空
                goto deal;
            }

            // 3.将代码写入 生成的唯一指定文件中(无后缀)
            file_name = file_util::UniqueFileName();
            if (!file_util::WriteFile(path_util::Src(file_name), code))
            {
                code_status = -2; // 内部代码出错
                goto deal;
            }

            // 4.进行编译和运行
            if (!compiler::compile(file_name)) // 通过返回值判断编译结果
            {
                code_status = -3; // 代码编译问题
                goto deal;
            }

            run_ret = runner::run(file_name, cpu_limit, mem_limit); // 通过返回值判断运行结果
            if (run_ret > 0)
            {
                code_status = run_ret; // 收到信号
                goto deal;             // 可以省略，后续就会执行deal代码段
            }
            else if (run_ret < 0)
            {
                code_status = -2; // 内部代码出错
            }
            else
            {
                code_status = 0; // 运行通过,并不意味着测试用例都能通过
                out["stdout"] = file_util::ReadFile(path_util::Stdout(file_name)).c_str();
                out["stderr"] = file_util::ReadFile(path_util::Stderr(file_name)).c_str();
            }
        deal: // 1.统一处理所有错误码
            out["status"] = code_status;
            out["status_reason"] = CodeToInfo(code_status, file_name).c_str();

            // 2.进行序列化,并将数据通过输出参数返回
            Json::StyledWriter writer;
            *json_out = writer.write(out);

            // 3.编译运行结束以后清空生成的所有临时文件
            // RemoveTempFile(file_name);
        }
    };

};